
/************************************************************************************************************
* File Name:SendCmdToDev.cpp
* Abstract :send command to camera
* 
* Version :1.0
* Author  :Liu Tengfei
* Date    :2013.12.1
*
* Shanghai Ruishi Machine Vision Technology Co., Ltd.
* All rights reserved.
*************************************************************************************************************/
#include "StdAfx.h"
#include "SendCmdToDev.h"
#include "GeneralFunction.h"

CSendCmdToDev::CSendCmdToDev(void)
{
	m_sockThis = INVALID_SOCKET;
	m_DevPort = 0;
	m_bAbort = false;
	m_backDataLen = 0;
	m_pchUserName = NULL;
	m_pchPassword = NULL;
	m_pchUserName = new char[USER_NAME_MAX_LENGTH];
	m_pchPassword = new char[USER_PASSWORD_MAX_LENGTH];
}

CSendCmdToDev::~CSendCmdToDev(void)
{
	Close();
	delete[] m_pchPassword;
	delete[] m_pchUserName;
}


void CSendCmdToDev::SetDevAddr(const char *pIP, unsigned short port)
{
	Reset();

	m_sDevIP = pIP;
	m_DevPort = port;
	m_backDataLen = 0;
}

int CSendCmdToDev::SetLoginInfo(const char *pUserName, const char *pPassword)
{
	DWORD nameLen = strlen(pUserName);
	DWORD passLen = strlen(pPassword);
	if ((nameLen>USER_NAME_MAX_LENGTH)||(passLen>USER_PASSWORD_MAX_LENGTH))
	{
		return -1;
	}

	strcpy_s(m_pchUserName,USER_NAME_MAX_LENGTH,pUserName);
	strcpy_s(m_pchPassword,USER_PASSWORD_MAX_LENGTH,pPassword);
	return 0;
}

int CSendCmdToDev::SendCMD(DWORD attribute, DWORD method)
{
	return SendCMD(attribute, method, NULL, 0);
}

int CSendCmdToDev::SendCMD(DWORD attribute, DWORD method, DWORD param)
{
	return SendCMD(attribute, method, (const char*)&param, sizeof(param));
}

int CSendCmdToDev::SendCMD(DWORD attribute, DWORD method, const char *pParam)
{
	return SendCMD(attribute, method, pParam, (int)(strlen(pParam) + 1));
}

int CSendCmdToDev::SendCMD(DWORD attribute, DWORD method, const char *pParam, int size)
{
	int nRet = -1;
	RoseekCmdPortHeadInfo		*pCmdHeadInfo = NULL;
	RoseekCmdBackMsgHeadInfo	*pBackHeadInfo = NULL;
	
	int flag = 0;

	m_backDataLen = 0;
	if (m_bAbort)
	{
		return -1;
	}
	for (int i = 0;i<2;i++)
	{
		//add command head information
		pCmdHeadInfo = (RoseekCmdPortHeadInfo*)m_pSendData;
		memset(pCmdHeadInfo,0,sizeof(RoseekCmdPortHeadInfo));
		pCmdHeadInfo->id = attribute;
		pCmdHeadInfo->method = method;

		//copy parameters
		if (size > 0)
		{
			memcpy(m_pSendData + sizeof(RoseekCmdPortHeadInfo) + 4, pParam, size);
		}
		*(UINT*)(m_pSendData + sizeof(RoseekCmdPortHeadInfo)) = size;

		int length = sizeof(RoseekCmdPortHeadInfo) + size + 4;

		if (sock_safeSend(m_sockThis, m_pSendData, length) != length)
		{
			Close();
			continue;
		}

		pBackHeadInfo = (RoseekCmdBackMsgHeadInfo*)m_pBackData;

		//receive back information
		if (sock_safeRecv(m_sockThis, (char*)pBackHeadInfo, sizeof(RoseekCmdBackMsgHeadInfo), 0) 
			!= sizeof(RoseekCmdBackMsgHeadInfo))
		{
			Close();
			continue;
		}

		memcpy(m_pchMsg,pBackHeadInfo->msg,256);
		m_dwResult = pBackHeadInfo->result;

		//receive back data length
		UINT recvDataLenTemp = 0;
		if (sock_safeRecv(m_sockThis, (char*)&recvDataLenTemp, 4, 0) != 4)
		{
			Close();
			continue;
		}

		UINT recvDataLen = recvDataLenTemp;
		if (recvDataLen>0)
		{
			if (recvDataLen > CMD_DATA_BUF_SIZE)
			{
				break;
			}

			//receive parameters
			if (sock_safeRecv(m_sockThis, m_pBackData, recvDataLen, 0) != (int)recvDataLen)
			{
				Close();
				continue;
			}	

		}

		m_backDataLen = recvDataLenTemp;
		nRet = 0;
		break;
	}

	if (0 != nRet)
	{
		m_bAbort = true;
		nRet = flag;
		Close();
	}

	return nRet;
}

int	CSendCmdToDev::LogInEncryption()
{
	RoseekLoginReqMsg *pReqInfo;
	RoseekLoginAnsMsg *pAnsInfo;
	int				nRet = 0;
	pReqInfo = (RoseekLoginReqMsg*)m_pSendData;
	pAnsInfo = (RoseekLoginAnsMsg*)m_pBackData;
	char			verifyCode[64];
	char			verifyString[256];
	int				length = 0;
	struct	md5_s ct_md5; 

	do 
	{
		//send log in message
		pReqInfo->id = CMD_LOGIN_REQUEST;
		pReqInfo->encrypt = ENCRYPTION_128BIT_MD5;
		strcpy_s(pReqInfo->userName, m_pchUserName);
		memset(pReqInfo->password,0,64);
		if (sock_safeSend(m_sockThis, m_pSendData, sizeof(RoseekLoginReqMsg)) !=  sizeof(RoseekLoginReqMsg))
		{
			nRet = -1;
			sprintf_s(pAnsInfo->msg,"Failed to send login request message");
			break;
		}

		//receive log in message;
		if (sock_safeRecv(m_sockThis, (char*)pAnsInfo, sizeof(RoseekLoginAnsMsg), 0) !=  sizeof(RoseekLoginAnsMsg))
		{
			nRet = -2;
			sprintf_s(pAnsInfo->msg,"Failed to receive login answer message");
			break;
		}
		
		if (strstr(pAnsInfo->msg,"nouce") == NULL)
		{
			nRet = pAnsInfo->answer;
			break;
		}

		strcpy_s(verifyCode,pAnsInfo->msg+6);

		length = strlen(verifyCode);

		if (length!= 16)
		{
			nRet = -3;
			break;
		}

		//generate verify string
		strcpy_s(verifyString,verifyCode);
		*(verifyString + length) = '\0';
		strcat_s(verifyString, m_pchUserName);
		strcat_s(verifyString, m_pchPassword);
		length += strlen(m_pchUserName) + strlen(m_pchPassword);
		*(verifyString + length) = '\0';

		//md5 verification
		InitMD5(&ct_md5);
		AddMD5(&ct_md5, &verifyString, length);
		EndMD5(&ct_md5);

		//send log in message
		pReqInfo->id = CMD_LOGIN_REQUEST;
		pReqInfo->encrypt = ENCRYPTION_128BIT_MD5;
		strcpy_s(pReqInfo->userName, m_pchUserName);
		memcpy(pReqInfo->password,ct_md5.p_digest,32);

		//send log in message
		if (sock_safeSend(m_sockThis, m_pSendData, sizeof(RoseekLoginReqMsg)) !=  sizeof(RoseekLoginReqMsg))
		{
			nRet = -1;
			sprintf_s(pAnsInfo->msg,"Failed to send login request message");
			break;
		}

		//receive log in message
		if (sock_safeRecv(m_sockThis, (char*)pAnsInfo, sizeof(RoseekLoginAnsMsg),0) !=  sizeof(RoseekLoginAnsMsg))
		{
			nRet = -2;
			sprintf_s(pAnsInfo->msg,"Failed to receive login answer message");
			break;
		}

		if (pAnsInfo->answer != LOGIN_SUCCESS)
		{
			nRet = pAnsInfo->answer;
			break;
		}

		nRet = 0;	
	} while (0);

	strcpy_s(m_pBackData + 4,256, pAnsInfo->msg);
	*(DWORD*)m_pBackData = nRet;

	//failed to login return -2;
	if (0 != nRet)
	{
		return SEND_CMD_LOGIN_FAILED;
	}
	return LOGIN_SUCCESS;
}

DWORD CSendCmdToDev::GetBackDataLen()
{
	return m_backDataLen;
}

const char* CSendCmdToDev::GetBackDataPtr()
{
	m_pBackData[CMD_DATA_BUF_SIZE] = '\0';
	return m_pBackData;
}

const char* CSendCmdToDev::GetBackMsgPtr()
{
	m_pchMsg[256] = '\0';
	return m_pchMsg;
}


DWORD CSendCmdToDev::GetBackDataUint32()
{
	DWORD value = *(DWORD*)m_pBackData;
	return value;
}

float CSendCmdToDev::GetBackDataFloat()
{
	DWORD value = *(DWORD*)m_pBackData;
	return *((float*)&value);
}

void CSendCmdToDev::Close()
{
	if (m_sockThis >= 0)
	{
		sock_close(m_sockThis);
		m_sockThis = INVALID_SOCKET;
	}
}

void CSendCmdToDev::Reset()
{
	Close();
	m_bAbort = false;
}

bool CSendCmdToDev::CreateAndConnect()
{
	Close();
	bool ret = false;

	do
	{
		if (m_sDevIP.empty())
		{
			break;
		}

		m_sockThis = sock_createTcp();
		if (m_sockThis < 0)
		{
			break;
		}
		

		sock_setWriteTimeout(m_sockThis, 20*1000);
		sock_setReadTimeout(m_sockThis, 20*1000);

		if (sock_connect(m_sockThis, m_sDevIP.c_str(), m_DevPort, 10000) < 0)
		{
			break;
		}

		ret = true;
	} while (0);

	if (!ret)
	{
		Close();
	}

	return ret;
}

std::string CSendCmdToDev::GetDevIP()
{
	return m_sDevIP;
}

unsigned short CSendCmdToDev::GetDevPort()
{
	return m_DevPort;
}

int CSendCmdToDev::Connect()
{
	int nRet = -1;

	if (m_sockThis < 0)
	{
		int flag = 0;
		for (int i = 0; i < 2; i++)
		{
			if (!CreateAndConnect())
			{
				flag = -1;
				break;
			}
			//log in
			flag = LogInEncryption();
			m_backDataLen = strlen((char*)m_pBackData);

			//failed to login,exit
			if (LOGIN_SUCCESS != flag)
			{
				Close();
				flag = -2;
				continue;
			}
		}

		nRet = flag;
	}
	else
	{
		nRet = LOGIN_SUCCESS;
	}
	
	return nRet;
}


